﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace eeZeeFTP
{
    public partial class Cntrl_DownloadItem : UserControl
    {
        private string sDestination = "";
        private string sFile = "";
        private FTPClient.FtpClient ftp;
        private long lSize = 0;
        private bool bBinary = true;
        private string sLastError = "";
        
        private int iProgress = 0;
        private Int64 lDownloadedBytes = 0;
        private Int64 lLastDownloadedBytes = 0;
        private double dBandWidth = 0;
        private DateTime dtStart;

        public bool bIsDownloading = false;
        public bool bOverwrite = false;
        public bool bStartWhenComplete = false;

        private bool bTransferIsDownload = true;

        private string sFileSize = "0 B";

        private double dSecondsGone = 0;

        private BackgroundWorker bw = new BackgroundWorker();
        private System.Timers.Timer timer = new System.Timers.Timer(1000);

        public delegate void MyDelegateLabel(Label myControl, string myArg);
        public delegate void MyDelegateProgressar(ProgressBar myControl, int myArg);

        public Int64 BytesDownloaded
        {
            get { return lDownloadedBytes; }
        }

        public Int64 FileSize
        {
            get { return lSize; }
        }

        public bool IsDownload
        {
            get { return bTransferIsDownload; }
            set { bTransferIsDownload = value; }
        }

        public Cntrl_DownloadItem(string sFile, string sDestination, long lFilesize, Image icon, FTPClient.FtpClient ftp_Client, bool bBinary, Encoding encoding)
        {
            SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);

            InitializeComponent();

            
            this.Dock = DockStyle.Top;

            this.ftp = ftp_Client;
            this.ftp.Encoding = encoding;

            this.sFile = sFile;
            this.sDestination = sDestination;
            this.lSize = lFilesize;

            sFileSize = Parameter.getTranferSpeed(lSize, "B");

            if(sFile.StartsWith("/"))
                lbl_Name.Text = sFile.Substring(sFile.LastIndexOf('/') + 1);
            else
                lbl_Name.Text = sFile.Substring(sFile.LastIndexOf('\\') + 1);

            toolTip1.SetToolTip(lbl_Name, sFile);
            pB_Image.BackgroundImage = icon;

            //this.SendToBack();

            timer.AutoReset = true;
            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);

            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                timer.Stop();

                if (sLastError != "" && lDownloadedBytes < lSize)
                {
                    lbl_Name.ForeColor = Color.Red;
                    lbl_Status.Text = sLastError;

                    ((Cntrl_Download)Parent.Parent.Parent).DownloadCompleted(this, DownloadStatus.Failed);
                }
                else
                {
                    lbl_Name.ForeColor = Color.Green;
                    progressBar1.Value = 100;
                    lbl_Progress.Text = "100 %";
                    lbl_Status.Text = "";

                    if (bStartWhenComplete)
                        Cntrl_DownloadItem_MouseDoubleClick(this, null);

                    ((Cntrl_Download)Parent.Parent.Parent).DownloadCompleted(this, DownloadStatus.Finished);
                }

                btn_Reload.BackgroundImage = Properties.Resources.arrow_refresh;
                toolTip1.SetToolTip(btn_Reload, "Wiederholen");

                bStartWhenComplete = false;
                bIsDownloading = false;
            }
            catch { }
        }

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            ftp.Respond += new FTPClient.FtpClient.RespondEventHandler(ftp_ClientRespond);

            try
            {
                BeginInvoke(new MyDelegateLabel(DelegateMethodLabel), new object[] { lbl_Status, "Verbinde mit Server: " + ftp.Server });
                ftp.Login();

                ftp.BinaryMode = bBinary;

                dtStart = DateTime.Now;

                BeginInvoke(new MyDelegateLabel(DelegateMethodLabel), new object[] { lbl_Status, "Verbindung aufgebaut. Starte Transfer..." });

                if (bTransferIsDownload)
                {
                    if (!bOverwrite && lDownloadedBytes < lSize)
                        ftp.Download(sFile, sDestination, true, lSize);
                    else
                        ftp.Download(sFile, sDestination, false, lSize);

                    bOverwrite = false;
                }
                else
                { 
                    string[] aFolders = sDestination.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    foreach (string s in aFolders)
                    {
                        try
                        {
                            ftp.ChangeDir(s);
                        }
                        catch
                        {
                            ftp.MakeDir(s);
                            ftp.ChangeDir(s);
                        }
                    }

                    System.IO.FileInfo fi = new System.IO.FileInfo(sFile);

                    ftp.Upload(sFile, sDestination + "/" + fi.Name, false, lSize);
                }
            }
            catch (Exception ex)
            {
                sLastError = ex.Message;
            }
            finally
            {
                if (ftp != null && ftp.loggedin)
                    ftp.Close();
            }

        }

        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            TimeSpan ts = DateTime.Now - dtStart;
            dtStart = DateTime.Now;

            lDownloadedBytes = ftp.iBytesDownloaded;
            DateTime dtFinished = new DateTime();

            if (lLastDownloadedBytes > 0 && ts.Ticks > 0)
            {
                //System.IO.File.AppendAllText(Parameter.TempPath + "\\log.txt", lDownloadedBytes + " - " + lLastDownloadedBytes + " - " + (ts.Seconds + ts.Milliseconds * 0.001) + "\r\n");
                dBandWidth = (lDownloadedBytes - lLastDownloadedBytes) / (ts.Seconds + ts.Milliseconds * 0.001);

                dSecondsGone += ts.TotalSeconds;

                if (dSecondsGone > 0 && lDownloadedBytes > ftp.offset)
                    dtFinished = dtFinished.AddSeconds((lSize - lDownloadedBytes) / ((lDownloadedBytes - ftp.offset) / dSecondsGone));
            }

            if (lSize > 0)
                iProgress = (int)(lDownloadedBytes * 100 / lSize);
            else
                iProgress = 0;

            BeginInvoke(new MyDelegateLabel(DelegateMethodLabel), new object[] { lbl_Progress, iProgress.ToString() + " %" });
            BeginInvoke(new MyDelegateProgressar(DelegateMethodProgressBar), new object[] { progressBar1, iProgress });
            BeginInvoke(new MyDelegateLabel(DelegateMethodLabel), new object[] { lbl_Status, Parameter.getTranferSpeed(lDownloadedBytes, "B") + " von " + sFileSize + " (" + Parameter.getTranferSpeed(dBandWidth, "B/s") + ")" + getRemainingTime(dtFinished) });

            lLastDownloadedBytes = lDownloadedBytes;
        }

        private string getRemainingTime(DateTime dtFinished)
        {
            string sRet = "";

            if (dtFinished.Year > 1)
                sRet += (dtFinished.Year - 1) + " Jahre ";

            if (dtFinished.Month > 1)
                sRet += (dtFinished.Month - 1) + " Monate ";

            if (dtFinished.Day > 1)
                sRet += (dtFinished.Day - 1) + " Tage ";

            if (dtFinished.Hour > 0)
                sRet += dtFinished.Hour + " h ";

            if (dtFinished.Minute > 0)
                sRet += dtFinished.Minute + " min ";

            if (dtFinished.Second > 0)
                sRet += dtFinished.Second + " s ";

            if(sRet.Length > 0)
                return " Zeit verbleibend: " + sRet;

            return "";
        }

        private void DelegateMethodLabel(Label myControl, string myCaption)
        {
            myControl.Text = myCaption;
        }

        private void DelegateMethodProgressBar(ProgressBar myControl, int myValue)
        {
            myControl.Value = myValue;
        }

        private void ftp_ClientRespond(object sender, FTPClient.RespondEventArgs e)
        {
            
        }

        public void btn_Reload_Click(object sender, EventArgs e)
        {
            lbl_Name.ForeColor = Color.Black;
            //lbl_Progress.Text = "0 %";
            //lbl_Status.Text = "";
            //progressBar1.Value = 0;
            toolTip1.SetToolTip(lbl_Name, sFile);
            sLastError = "";

            if (!bIsDownloading)
                ((Cntrl_Download)Parent.Parent.Parent).DownloadCompleted(this, DownloadStatus.Open);
            else
            {
                timer.Stop();

                ftp.CancelFiletransfer = true;
                //ftp.Close();
                //ftp.Dispose();
                lbl_Name.ForeColor = Color.Red;
                sLastError = "Angehalten";
                bOverwrite = false;
            }
            //btn_Reload.Enabled = false;
        }

        public void btn_Delete_Click(object sender, EventArgs e)
        {
            timer.Stop();

            ftp.CancelFiletransfer = true;

            bw = null;
            ftp.Dispose();

            this.Dispose();
        }

        private void btn_OpenPath_Click(object sender, EventArgs e)
        {
            try
            {
                ProcessStartInfo Info = new ProcessStartInfo("explorer.exe", sDestination.Substring(0, sDestination.LastIndexOf('\\')));
                Info.ErrorDialog = true;
                Process.Start(Info);
            }
            catch { }
        }

        private void Cntrl_DownloadItem_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            try
            {
                ProcessStartInfo Info = new ProcessStartInfo(sDestination);
                Info.ErrorDialog = true;
                Process.Start(Info);
            }
            catch { }
        }

        private void Cntrl_DownloadItem_MouseEnter(object sender, EventArgs e)
        {
            this.lbl_Status.ForeColor = Color.White;
            this.BackgroundImage = eeZeeFTP.Properties.Resources.menubutton_blue;
        }

        private void Cntrl_DownloadItem_MouseLeave(object sender, EventArgs e)
        {
            this.lbl_Status.ForeColor = Color.Black;
            this.BackgroundImage = eeZeeFTP.Properties.Resources.menubutton_lightblue;
        }

        internal void StartDownloading()
        {
            //this.SendToBack();
            bTransferIsDownload = true;
            pB_UpDownload.Image = eeZeeFTP.Properties.Resources.server_to_computer;
            toolTip1.SetToolTip(pB_UpDownload, "Download von: " + ftp.Server + Environment.NewLine + "Ziel: " + sDestination);

            startTransfer();
        }

        internal void StartUploading()
        {
            //this.SendToBack();
            bTransferIsDownload = false;
            pB_UpDownload.Image = eeZeeFTP.Properties.Resources.computer_to_server;
            toolTip1.SetToolTip(pB_UpDownload, "Upload nach: " + ftp.Server + Environment.NewLine + "Ziel: " + sDestination);

            startTransfer();
        }

        private void startTransfer()
        {
            timer.Start();

            bIsDownloading = true;
            dSecondsGone = 0;

            btn_Reload.BackgroundImage = Properties.Resources.control_pause;
            toolTip1.SetToolTip(btn_Reload, "Anhalten");

            bw.RunWorkerAsync();
        }
    }
} 
